package com.example.lib_core.task

import io.reactivex.Maybe
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers

/**
 * 带结果的任务
 */
open class SingleTask<RESULT> : ITask {

    private var disposable: Disposable? = null
    var isCancelled: Boolean = false
        private set

    private var successAction: ((RESULT) -> Unit)? = null
    private var errorAction: ((Throwable) -> Unit)? = null
    private var beforeAction: (() -> Unit)? = null
    private var interruptedAction: (() -> Unit)? = null

    private var isSuccess: Boolean = false
    private var running = false
    private var hasError = false

    private var runnable: (SingleTask<*>) -> RESULT = { onTaskRun() }

    val isRunning: Boolean
        get() = disposable != null && !disposable!!.isDisposed && running && !isCancelled


    class NullableResult<RESULT>(val result: RESULT)

    /**
     * 启动任务
     */
    fun start(): SingleTask<RESULT> {
        if (isRunning)
            throw IllegalStateException("already started")

        val current = this
        hasError = false
        isCancelled = false
        isSuccess = false
        running = true

        // BEFORE
        current.onTaskBefore()
        beforeAction?.invoke()

        if (isCancelled)
            return this

        val obs = Maybe
            .create<NullableResult<RESULT>> { emitter ->
                try {
                    if (isCancelled)
                        throw RuntimeException("task is already cancelled")

                    val result = runnable.invoke(this)
                    emitter.onSuccess(NullableResult(result))

                } catch (e: Exception) {
                    if (!isCancelled) {
                        try {
                            emitter.onError(e)
                        }catch (e: Exception) {
                            e.printStackTrace()
                        }
                    }
                }
            }
            .subscribeOn(Schedulers.newThread())
            .observeOn(if (Task.ANDROID_PLATFORM) AndroidSchedulers.mainThread() else Schedulers.computation())
            .unsubscribeOn(if (Task.ANDROID_PLATFORM) AndroidSchedulers.mainThread() else Schedulers.computation())
            .doOnDispose {

                // CANCEL
                if (!isSuccess && !hasError) {
                    Single.just(isCancelled)
                        .subscribeOn(Schedulers.newThread())
                        .observeOn(if (Task.ANDROID_PLATFORM) AndroidSchedulers.mainThread() else Schedulers.computation())
                        .subscribe { isCancelled ->
                            if (isCancelled) {
                                onTaskInterrupted()
                                interruptedAction?.invoke()
                            }
                        }
                }
            }

        if (isCancelled) {
            println("start cancelled!!!!!!!!!!!!!!2222")
            return this
        }


        disposable = obs.subscribe(
            // SUCCESS
            { result ->
                if (!isCancelled) {
                    running = false
                    isSuccess = true
                    current.onTaskSuccess(result.result)
                    successAction?.invoke(result.result)
                }
            },
            // ERROR
            { throwable ->
                if (!isCancelled) {
                    running = false
                    isSuccess = false
                    hasError = true
                    current.onTaskError(throwable)
                    errorAction?.invoke(throwable)
                }
            })
        return this
    }

    fun start(runnable: (SingleTask<*>) -> RESULT): SingleTask<RESULT> {
        this.runnable = runnable
        return start()
    }

    /**
     * 主动中断任务
     */
    fun cancel() {
        isCancelled = true

        if (disposable == null) {
            println("disposable is null")
        }
        disposable?.dispose()
    }

    /**
     * 事件：执行前
     */
    fun before(action: () -> Unit): SingleTask<RESULT> {
        beforeAction = action
        return this
    }

    /**
     * 事件：任务成功
     */
    fun success(action: (RESULT) -> Unit): SingleTask<RESULT> {
        successAction = action
        return this
    }

    /**
     * 事件：任务出错
     */
    fun error(action: (Throwable) -> Unit): SingleTask<RESULT> {
        errorAction = action
        return this
    }

    /**
     * 事件：主动中断
     */
    fun interrupted(action: () -> Unit): SingleTask<RESULT> {
        interruptedAction = action
        return this
    }

    protected fun onTaskBefore() {}

    /**
     * 任务执行信息，如果继承SingleTask，则重构此方法
     */
    @Throws(Exception::class)
    protected open fun onTaskRun(): RESULT {
        throw NotImplementedError()
    }

    protected fun onTaskSuccess(result: RESULT) {}

    protected fun onTaskError(error: Throwable) {}

    protected fun onTaskInterrupted() {}

    private var proxy = object : ITaskProxy {
        override fun start() {
            this@SingleTask.start()
        }

        override fun stop() {
            this@SingleTask.cancel()
        }
    }

    override fun getProxy(): ITaskProxy {
        return proxy
    }
}